package com.bicon.botu.mall.component.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.enums.SqlLike;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.bicon.botu.mall.component.common.BaseConstants;
import com.bicon.botu.mall.component.entity.Dictionary;
import com.bicon.botu.mall.component.dto.AreaDictionaryCodeEnum;
import com.bicon.botu.mall.component.dto.DictionaryNodeDTO;
import com.bicon.botu.mall.component.dto.KeyValueDTO;
import com.bicon.botu.mall.component.mapper.ComponentDictionaryMapper;
import com.bicon.botu.mall.component.service.IComponentDictionaryService;
import com.bicon.botu.core.base.bean.GlobalRedisTemplate;
import com.bicon.botu.core.base.common.Constants;
import com.bicon.botu.core.base.common.entity.BaseResult;
import com.bicon.botu.core.base.common.utils.BeanMapper;
import com.bicon.botu.core.base.common.utils.JsonUtil;
import com.bicon.botu.core.base.common.utils.NodeUtil;
import com.bicon.botu.core.base.common.utils.StringUtils;
import com.bicon.botu.core.base.repository.redis.RedisHandler;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * <p>
 * 存放常用配置参数、地区、年龄段、性别、指标类型等数据 服务实现类
 * </p>
 *
 * @author tandk
 * @since 2017-07-31
 */
@Service
public class ComponentDictionaryServiceImpl extends ServiceImpl<ComponentDictionaryMapper, com.bicon.botu.mall.component.entity.Dictionary> implements IComponentDictionaryService {

    @Autowired
    RedisHandler redisHandler;

    @Autowired
    private GlobalRedisTemplate globalRedisTemplate;


    /**
     * 初始化字典缓存
     *
     * @return
     */
    @Override
    public boolean initDictionaryRedis() {
        List<com.bicon.botu.mall.component.entity.Dictionary> keyValueDictList = new com.bicon.botu.mall.component.entity.Dictionary()
                .selectList(new EntityWrapper().eq("logic_delete", Constants.DEL_LOGIC_NORMAL));
        Map<String, String> map = new HashMap<>(16);
        keyValueDictList.stream().forEach(dictionary -> map.put(Integer.toString(dictionary.getId()), dictionary.getDictionaryName()));
        boolean result = redisHandler.getGlobalRedisTemplate().remove(BaseConstants.BOTU_BASE_DICTIONARY, "");
        if(!result){
            return result;
        }
        result = redisHandler.getGlobalRedisTemplate().cacheHashAll(BaseConstants.BOTU_BASE_DICTIONARY, "", map);
        return result;
    }

    /**
     * 初始化基础字典缓存
     *
     * @return
     */
    @Override
    public boolean initBaseDictionaryRedis() {
        com.bicon.botu.mall.component.entity.Dictionary dictionary = new com.bicon.botu.mall.component.entity.Dictionary();
        // 写入Key Value型（type为1的配置）配置
        List<com.bicon.botu.mall.component.entity.Dictionary> keyValueDictList = dictionary.selectList(new EntityWrapper().eq("type", "1").eq("logic_delete", Constants.DEL_LOGIC_NORMAL));

        this.globalRedisTemplate.delete(BaseConstants.BOTU_BASE_DICTIONARY_BASE_CONFIG);

        this.globalRedisTemplate.executePipelined(new RedisCallback<List<String>>() {
            @Override
            public List<String> doInRedis(RedisConnection connection) throws DataAccessException {
                for (int i = 0; i < keyValueDictList.size(); i++) {
                    connection.hSet(globalRedisTemplate.getKeySerializer().serialize(BaseConstants.BOTU_BASE_DICTIONARY_BASE_CONFIG),
                            globalRedisTemplate.getKeySerializer().serialize(keyValueDictList.get(i).getDictionaryCode()),
                            globalRedisTemplate.getKeySerializer().serialize(keyValueDictList.get(i).getContent()));
                }
                return null;
            }
        });

        // 删除旧缓存
        Set<String> hashKeySet = this.globalRedisTemplate.keys(BaseConstants.BOTU_BASE_DICTIONARY_HASH_CONFIG + ":*");
        this.globalRedisTemplate.delete(hashKeySet);

        // 写入List型配置（type为2的配置）
        List<com.bicon.botu.mall.component.entity.Dictionary> hashDictList = dictionary.selectList(new EntityWrapper().eq("type", "2").eq("logic_delete", Constants.DEL_LOGIC_NORMAL));
        Map<String, Map<String, com.bicon.botu.mall.component.entity.Dictionary>> hashDictMap = this.parseHashDict(hashDictList);
        this.globalRedisTemplate.executePipelined(new RedisCallback<List<String>>() {
            @Override
            public List<String> doInRedis(RedisConnection connection) throws DataAccessException {
                Iterator<String> keyIterator = hashDictMap.keySet().iterator();
                while (keyIterator.hasNext()) {
                    String key = keyIterator.next();
                    Map<String, com.bicon.botu.mall.component.entity.Dictionary> subMap = hashDictMap.get(key);
                    //
                    if (subMap.size() > 0) {
                        Iterator<String> subIterator = subMap.keySet().iterator();
                        Map<byte[], byte[]> byteMap = new HashMap<>();
                        while (subIterator.hasNext()) {
                            String subKey = subIterator.next();
                            byteMap.put(globalRedisTemplate.getKeySerializer().serialize(subKey), globalRedisTemplate.getValueSerializer().serialize(JSON.toJSONString(subMap.get(subKey))));
                        }
                        connection.hMSet(globalRedisTemplate.getKeySerializer().serialize(BaseConstants.BOTU_BASE_DICTIONARY_HASH_CONFIG + ":" + key), byteMap);
                    }
                }
                return null;
            }
        });

        return true;
    }


    /**
     * 新增字典
     *
     * @param dictionary
     * @return
     */
    @Override
    public boolean addDictionary(com.bicon.botu.mall.component.entity.Dictionary dictionary) {
        boolean b = insert(dictionary);
        if (b) {
            // 更新字典path
            dictionary.setPath(dictionary.getPath() + (StringUtils.isNotEmpty(dictionary.getPath()) ? ":" : "") + dictionary.getId());
            b = dictionary.updateById();
            b = this.cacheDictionary(dictionary);
            //保存至缓存
            redisHandler.getGlobalRedisTemplate()
                    .cacheHash(BaseConstants.BOTU_BASE_DICTIONARY, "", Integer.toString(dictionary.getId()), dictionary.getDictionaryName());
        }
        return b;
    }

    /**
     * 删除字典
     *
     * @param id
     * @return
     */
    @Override
    public boolean delDictionary(int id) {
        com.bicon.botu.mall.component.entity.Dictionary dictionary = new com.bicon.botu.mall.component.entity.Dictionary();
        dictionary.setId(id);
        dictionary = dictionary.selectById();
        boolean b = dictionary.deleteById();
        this.removeDictionary(dictionary);
        b = redisHandler.getGlobalRedisTemplate().removeHash(BaseConstants.BOTU_BASE_DICTIONARY, "", Integer.toString(dictionary.getId()));
        return b;
    }

    /**
     * 修改字典
     *
     * @param dictionary
     * @return
     */
    @Override
    public boolean updateDictionary(com.bicon.botu.mall.component.entity.Dictionary dictionary) {
        com.bicon.botu.mall.component.entity.Dictionary oldDict = dictionary.selectById();
        boolean b = dictionary.updateById();
        this.removeDictionary(oldDict);
        b = this.cacheDictionary(dictionary);
        //保存至缓存
        b = redisHandler.getGlobalRedisTemplate()
                .cacheHash(BaseConstants.BOTU_BASE_DICTIONARY, "", Integer.toString(dictionary.getId()), dictionary.getDictionaryName());
        return b;
    }

    /**
     * 初始化【地区字典】到redis
     */
    @Override
    public boolean initAreaToRedis() {
        // 分别查询父亲（国家、省、市、区）
        Map<String, Object> m = AreaDictionaryCodeEnum.getKeyValueMap();
        for (String name : m.keySet()) {
            // 查询此父亲的所有孩子
            List<com.bicon.botu.mall.component.entity.Dictionary> list = selectList(new EntityWrapper<com.bicon.botu.mall.component.entity.Dictionary>().eq("type", 0).eq("level", m.get(name)));
            // 遍历所有孩子，将相同父亲的孩子组合到一起放入map，key为父亲id
            Map<Integer, List<KeyValueDTO>> allMap = new HashMap<>();
            Integer parentId;
            for (com.bicon.botu.mall.component.entity.Dictionary d : list) {
                parentId = d.getParentId();
                // 判断allMap中是否已包含此父亲的map，是则加入到此map，不是则新增此父亲map并加入
                if (allMap.containsKey(parentId)) {
                    allMap.get(parentId).add(new KeyValueDTO(d.getDictionaryCode() + "", d.getDictionaryName()));
                } else {
                    List<KeyValueDTO> keyValueDTOList = new ArrayList<>();
                    keyValueDTOList.add(new KeyValueDTO(d.getDictionaryCode() + "", d.getDictionaryName()));
                    allMap.put(parentId, keyValueDTOList);
                }
            }
            // 遍历allMap，将子map转为json存入新map
            Set set = allMap.keySet();
            Iterator<Integer> iterator = set.iterator();
            Map<String, String> map = new HashMap<>();
            while (iterator.hasNext()) {
                Integer k = iterator.next();
                map.put(k + "", JsonUtil.toJson(allMap.get(k)));
            }
            // 分别缓存国家、省、市、区对应下的所有孩子json集合map
            redisHandler.getGlobalRedisTemplate().cacheHashAll(name, "", map);
        }
        return true;
    }

    /**
     * 初始化【擅长领域】到redis
     */
    @Override
    public boolean initAdvantageAreaToRedis() {
        // 分别查询父亲
        com.bicon.botu.mall.component.entity.Dictionary parentDictionary = new com.bicon.botu.mall.component.entity.Dictionary().selectOne(new EntityWrapper().eq("dictionary_code", "ADVANTAGE_AREA").eq("logic_delete", Constants.DEL_LOGIC_NORMAL));
        List<com.bicon.botu.mall.component.entity.Dictionary> dictionaryList = new com.bicon.botu.mall.component.entity.Dictionary().selectList(new EntityWrapper().eq("parent_id",parentDictionary.getId()).eq("logic_delete", Constants.DEL_LOGIC_NORMAL));
        List<String> keyValueDTOList = new ArrayList<>();
        Map<String,String> map = new HashMap<>();
        dictionaryList.stream().forEach(dictionaryArea ->{
            //查询孩子
            List<com.bicon.botu.mall.component.entity.Dictionary> dictionaries = selectList(new EntityWrapper<com.bicon.botu.mall.component.entity.Dictionary>().eq("parent_id",dictionaryArea.getId()));
            List<KeyValueDTO<String>> keyValueDTOS = new ArrayList<>();
            dictionaries.stream().forEach(dictionary ->{
                KeyValueDTO<String> keyValueDTO =new KeyValueDTO<String>();
                keyValueDTO.setKey(Integer.toString(dictionary.getId()));
                keyValueDTO.setValue(dictionary.getDictionaryName());
                keyValueDTOS.add(keyValueDTO);
            });
            map.put(Integer.toString(dictionaryArea.getId()),JSONObject.toJSONString(keyValueDTOS));
            KeyValueDTO<String> keyValueDTO =new KeyValueDTO<String>();
            keyValueDTO.setKey(Integer.toString(dictionaryArea.getId()));
            keyValueDTO.setValue(dictionaryArea.getDictionaryName());
            keyValueDTOList.add(JSONObject.toJSONString(keyValueDTO));
        });
        redisHandler.getGlobalRedisTemplate().remove(BaseConstants.BOTU_BASE_DICTIONARY,":advantage_area:first");
        redisHandler.getGlobalRedisTemplate().remove(BaseConstants.BOTU_BASE_DICTIONARY,":advantage_area:second");
        //缓存父级
        redisHandler.getGlobalRedisTemplate().cacheList(BaseConstants.BOTU_BASE_DICTIONARY,":advantage_area:first",keyValueDTOList);
       //缓存子集
        redisHandler.getGlobalRedisTemplate().cacheHashAll(BaseConstants.BOTU_BASE_DICTIONARY,":advantage_area:second",map);
        return true;
    }


    /**
     * 从redis中查询省、市、区
     *
     * @param code     查询（省、市、区）对应的code
     * @param parentId 父地区id
     */
    @Override
    public BaseResult findAreaFromRedis(String code, int parentId) {
        String json = redisHandler.getGlobalRedisTemplate().getHash(code, "", parentId + "");
        List<KeyValueDTO> list = JsonUtil.fromJson(json, List.class);
        return new BaseResult(Constants.RESPONSE_CODE_200, Constants.RESPONSE_MESSAGE_200, list);
    }

    /**
     * 根据父字典code获取字典集合
     *
     * @param code 父字典code
     * @return 子字典集合
     */
    @Override
    public List<com.bicon.botu.mall.component.entity.Dictionary> findListByParentCode(String code) {
        com.bicon.botu.mall.component.entity.Dictionary dictionary = new com.bicon.botu.mall.component.entity.Dictionary().selectOne(new EntityWrapper().eq("dictionary_code", code).eq("logic_delete", Constants.DEL_LOGIC_NORMAL));
        List<String> dictJsonList = this.globalRedisTemplate.opsForHash().values(BaseConstants.BOTU_BASE_DICTIONARY_HASH_CONFIG + ":" + code);
        List<com.bicon.botu.mall.component.entity.Dictionary> result = new ArrayList<com.bicon.botu.mall.component.entity.Dictionary>();
        for (String dictJson : dictJsonList) {
            result.add(JSON.parseObject(dictJson, com.bicon.botu.mall.component.entity.Dictionary.class));
        }
        return result;
    }

    /**
     * 根据父id获取字典集合
     *
     * @param parentId 父id
     * @return 子字典集合
     */
    @Override
    public List<DictionaryNodeDTO> findAllDictionaryNode(Integer parentId, String code) {
        if (parentId != null && parentId >= 0) {
            List<com.bicon.botu.mall.component.entity.Dictionary> dictionaryList = new com.bicon.botu.mall.component.entity.Dictionary().selectList(new EntityWrapper().like("path", parentId + ":", SqlLike.RIGHT));
            List<DictionaryNodeDTO> dictionaryDTOList = BeanMapper.mapList(dictionaryList, DictionaryNodeDTO.class);
            return new NodeUtil<DictionaryNodeDTO>().getChildNodes(dictionaryDTOList, parentId + "");
        } else if (StringUtils.isNotEmpty(code)) {
            //获取此code对应的字典
            com.bicon.botu.mall.component.entity.Dictionary dictionary = new com.bicon.botu.mall.component.entity.Dictionary().selectOne(new EntityWrapper().eq("dictionary_code", code));
            //获取此code对应的字典及子字典集合
            List<com.bicon.botu.mall.component.entity.Dictionary> dictionaryList = new com.bicon.botu.mall.component.entity.Dictionary().selectList(new EntityWrapper().eq("path", dictionary.getId() + "").or().like("path", dictionary.getId() + ":", SqlLike.RIGHT));
            List<DictionaryNodeDTO> dictionaryDTOList = BeanMapper.mapList(dictionaryList, DictionaryNodeDTO.class);
            return new NodeUtil<DictionaryNodeDTO>().getChildNodes(dictionaryDTOList, dictionary.getId() + "");
        }
        return null;
    }


    /**
     * 根据id查询字典
     *
     * @return 字典
     */
    @Override
    public KeyValueDTO<String> findDictionaryFromRedis(String id){
        String result = redisHandler.getGlobalRedisTemplate().getHash(BaseConstants.BOTU_BASE_DICTIONARY,"",id);
        return JSONObject.parseObject(result,KeyValueDTO.class);
    }


    /**
     * 将Hash型的配置转换成Map<String,Map<String,Dictionary>> 结构，用于redis存储。
     *
     * @param hashDictList type为2的Dictionary对象
     * @return
     */
    private Map<String, Map<String, com.bicon.botu.mall.component.entity.Dictionary>> parseHashDict(List<com.bicon.botu.mall.component.entity.Dictionary> hashDictList) {
        if (CollectionUtils.isEmpty(hashDictList)) {
            return null;
        }
        Map<String, Map<String, com.bicon.botu.mall.component.entity.Dictionary>> result = new HashMap<String, Map<String, com.bicon.botu.mall.component.entity.Dictionary>>();

        for (int i = 0; i < hashDictList.size(); i++) {
            com.bicon.botu.mall.component.entity.Dictionary dict = hashDictList.get(i);
            String parentCode = "";
            //获取dict的父code。
            if (dict.getParentId() != 0) {
                for (int j = 0; j < hashDictList.size(); j++) {
                    if (hashDictList.get(j).getId() == dict.getParentId()) {
                        parentCode = hashDictList.get(j).getDictionaryCode();
                    }
                }
            }

            if (StringUtils.isNotEmpty(parentCode)) {
                Map<String, com.bicon.botu.mall.component.entity.Dictionary> dictMap = result.get(parentCode);
                if (dictMap == null) {
                    dictMap = new HashMap<String, com.bicon.botu.mall.component.entity.Dictionary>();
                    result.put(parentCode, dictMap);
                }
                dictMap.put(String.valueOf(dict.getId()), dict);
            } else {
                result.put(dict.getDictionaryCode(), new HashMap<String, com.bicon.botu.mall.component.entity.Dictionary>());
            }
        }
        return result;
    }

    /**
     * 设置类型为1和2的字典缓存
     *
     * @param dictionary 字典
     * @return
     */
    private boolean cacheDictionary(com.bicon.botu.mall.component.entity.Dictionary dictionary) {
        if (dictionary.getType() == 1) {
            redisHandler.getGlobalRedisTemplate().cacheHash(BaseConstants.BOTU_BASE_DICTIONARY_BASE_CONFIG, "", dictionary.getDictionaryCode(), dictionary.getContent());
        } else if (dictionary.getType() == 2) {
            if (dictionary.getParentId() > 0) {
                com.bicon.botu.mall.component.entity.Dictionary parent = dictionary.selectById(dictionary.getParentId());
                KeyValueDTO<String> keyValueDTO = new KeyValueDTO<String>();
                keyValueDTO.setKey(Integer.toString(dictionary.getId()));
                keyValueDTO.setValue(dictionary.getDictionaryName());
                redisHandler.getGlobalRedisTemplate().cacheHash(BaseConstants.BOTU_BASE_DICTIONARY_HASH_CONFIG, ":" + parent.getDictionaryCode(),
                        String.valueOf(keyValueDTO.getKey()), JSON.toJSONString(keyValueDTO));
            }
        }
        return true;
    }

    private boolean removeDictionary(com.bicon.botu.mall.component.entity.Dictionary dictionary) {
        if (dictionary.getType() == 1) {
            redisHandler.getGlobalRedisTemplate().removeHash(BaseConstants.BOTU_BASE_DICTIONARY_BASE_CONFIG, "", dictionary.getDictionaryCode());
        } else {
            if (dictionary.getParentId() != 0) {
                Dictionary parent = dictionary.selectById(dictionary.getParentId());
                redisHandler.getGlobalRedisTemplate().removeHash(BaseConstants.BOTU_BASE_DICTIONARY_HASH_CONFIG, ":" + parent.getDictionaryCode(), String.valueOf(dictionary.getId()));
            } else {
                redisHandler.getLocalRedisTemplate().remove(BaseConstants.BOTU_BASE_DICTIONARY_HASH_CONFIG, ":" + dictionary.getDictionaryCode());
            }

        }

        return true;
    }
}
